import fcntl
import os
from . import server
from . import client_lib
import errno
import socket
import pyinotify


class CloseWatcher(pyinotify.ProcessEvent):
  isDone = False

  def process_IN_CLOSE_WRITE(self, event):
    self.isDone = True

def make_breaker(event_handler):
  def breaker(notifier):
    return event_handler.isDone
  return breaker

def wait_for_file_write(fname):
  wm = pyinotify.WatchManager()
  cw = CloseWatcher()
  wm.add_watch(fname, pyinotify.IN_CLOSE_WRITE, cw) 
  pyinotify.Notifier(wm).loop(make_breaker(cw))

def is_server_started(f):
  try:
    fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
  except IOError as e:
    return e.errno == errno.EAGAIN
  print("file watching server not started.")
  return False




def getClient(config):
  """

  Args:
    config: config.RepoConfig, The repository configuration.
  """
  config.ensure_graph_directory()
  dieset = set()
  dieset.add(config.get_graph_filename())
  just_started = False
  alive_log = os.open("bin/__graph__/watcher_alive_log", os.O_WRONLY | os.O_CREAT)
  dieset.add('bin/__graph__/watcher_pid')

  def start_server():
    def callback():
      # Write pid
      fd_pid = open('bin/__graph__/watcher_pid', "w+")
      fd_pid.write(str(os.getpid()) + '\n')
      fd_pid.close()

    server.start_server(callback, dieset)

  if not is_server_started(alive_log): 
    just_started = True
    alive_log = os.fdopen(alive_log, "w+") #convert to file object
    # got lock: must spawn server (server will carry lock on for us)
    f = open('bin/__graph__/watcher_pid', "w+")
    f.close()
    daemonize(start_server, alive_log)

    wait_for_file_write('bin/__graph__/watcher_pid')
    alive_log.close()
    with open("bin/__graph__/watcher_pid", "r") as f:
      print("server started on pid: " + str(f.read()))

  with open("bin/__graph__/watcher_port") as a:
    client = client_lib.ClientLib(int(a.read()))
    client.just_started = just_started
    return client

def daemonize(cmd, log_fd):
  """
  One extra fork for good luck. 
  (actually it wasn't daemonizing quite right because this one lives on)
  """

  pid = os.fork()
  if (pid == 0):
    # child 1
    pid = os.fork()
    if (pid == 0):
      # child 2
      os.setsid()
      pid = os.fork()
      if (pid == 0):
        # child 3
        os.umask(0o022)
        fd_inp = open(os.devnull, "r")
        os.dup2(fd_inp.fileno(), 0)
        os.dup2(log_fd.fileno(), 1)
        os.dup2(log_fd.fileno(), 2)
        cmd()
        os._exit(0)
      else:
        # parent 3
        os._exit(0)
    else:
      # parent 2
      os._exit(0)
  else:
    # parent 1
    pass
  os.wait()

if __name__ == '__main__':
  def daemonize(cmd, log_fd):
    cmd()
  getClient(".")

